#include <mutex>
using std::mutex;
#include <atomic>
using namespace std;

template <class T>
class shared_ptr{
private:
    T* _ptr;
    int* _count;
    mutex* _pm;
public:
    shared_ptr(T* ptr = nullptr): _ptr(ptr), _count(new int(1)), _pm(new mutex()) {}
    shared_ptr(const shared_ptr& sp): _ptr(sp._ptr), _count(sp._count), _pm(sp._pm){
        add_ref_count();
    }
    ~shared_ptr(){
        release();
    }

    shared_ptr& operator=(const shared_ptr& sp){
        if(_ptr != sp._ptr){
            release();
            _ptr = sp._ptr;
            _count = sp._count;
            _pm = sp._pm;
            add_ref_count();
        }
        return *this;
    }

public:
    T& operator*(){ return *_ptr;}
    T* operator->(){ return _ptr;}

public:
    int use_count(){ return *_count;}
    T* get(){return _ptr;}
private:
    void add_ref_count(){
        _pm->lock();
        ++(*_count);
        _pm->unlock();
    }
    void release(){
        bool flag = false;
        _pm->lock();
        if(--(*_count) == 0){
            flag = true;
            delete _ptr;
            delete _count;
        }
        _pm->unlock();
        if(flag) delete _pm;
    }
};